/***
 * encodeing: UTF-8
*/

#include "Room.h"
//#include "DB.h"

/**
 * database with room
*/
RoomBean::RoomBean()
{
	int db = sqlite3_open_v2(dataPath, &(roomDatabase), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);

	if (db)
	{
		fprintf(stderr, "[ERROR] Failed to open database %s\n.", sqlite3_errmsg(roomDatabase));
		exit(-1);
	}
	else
	{
		const char *main =
			"CREATE TABLE IF NOT EXISTS roombean(\
			time INTEGER,\
			type INTEGER,\
			source INTEGER,\
			destination INTEGER,\
			queryType INTEGER,\
			responseType INTEGER,\
			roomId INTEGER,\
			state INTEGER,\
			targetT REAL,\
			targetW INTEGER,\
			nowT REAL,\
			nowW INTEGER,\
			initT REAL,\
			fee REAL,\
			power INTEGER\
			)";
		const char *back = "CREATE TABLE IF NOT EXISTS roombean_back(\
			time INTEGER,\
			type INTEGER,\
			source INTEGER,\
			destination INTEGER,\
			queryType INTEGER,\
			responseType INTEGER,\
			roomId INTEGER,\
			state INTEGER,\
			targetT REAL,\
			targetW INTEGER,\
			nowT REAL,\
			nowW INTEGER,\
			initT REAL,\
			fee REAL,\
			power INTEGER\
			)";
		int result = sqlite3_prepare_v2(roomDatabase, main, -1, &(stmt), NULL);
		if (result == SQLITE_OK)
		{
			std::cout << "[INFO] Room table loaded.\n";
			sqlite3_step(stmt);
		}
		else
		{
			std::cout << "[ERROR] Failed to load room table.\n";
		}
		sqlite3_finalize(stmt);

		result = sqlite3_prepare_v2(roomDatabase, back, -1, &(stmt), NULL);
		if (result == SQLITE_OK)
		{
			std::cout << "[INFO] Room table 2 loaded.\n";
			sqlite3_step(stmt);
		}
		else
		{
			std::cout << "[ERROR] Failed to load room table 2.\n";
		}
		sqlite3_finalize(stmt);
	}
}

/**
 * insert room information
*/
bool RoomBean::Insert(Room *room)
{
	char main_sql[SQL_LENGTH] = {};

	sprintf_s(main_sql,
			  "INSERT INTO roombean VALUES(\
			%d,%d,%d,%d,%d,%d,%d,%d,%lf,%d,%lf,%d,%lf,%lf,%d)",
			  (int)room->getTime(),
			  (int)room->getType(),
			  (int)room->getSource(),
			  (int)room->getDestination(),
			  (int)room->getQueryType(),
			  (int)room->getResponseType(),
			  room->getRoomId(),
			  (int)room->getRoomState(),
			  room->getTargetT(),
			  (int)room->getTargetW(),
			  room->getCurrentT(),
			  (int)room->getCurrentW(),
			  room->getInitT(),
			  room->getBill(),
			  room->getPower());
	int result = sqlite3_prepare_v2(roomDatabase, main_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		std::cout << "[INFO] Room inserted.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to insert room.\n";
		return false;
	}
	sqlite3_finalize(stmt);

	char back_sql[SQL_LENGTH] = {};

	sprintf_s(back_sql,
			  "INSERT INTO roombean_back VALUES(\
			%d,%d,%d,%d,%d,%d,%d,%d,%lf,%d,%lf,%d,%lf,%lf,%d)",
			  (int)room->getTime(),
			  (int)room->getType(),
			  (int)room->getSource(),
			  (int)room->getDestination(),
			  (int)room->getQueryType(),
			  (int)room->getResponseType(),
			  room->getRoomId(),
			  (int)room->getRoomState(),
			  room->getTargetT(),
			  (int)room->getTargetW(),
			  room->getCurrentT(),
			  (int)room->getCurrentW(),
			  room->getInitT(),
			  room->getBill(),
			  room->getPower());
	int result2 = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result2 == SQLITE_OK)
	{
		std::cout << "[INFO] Room inserted.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to insert room.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

RoomBean::~RoomBean()
{
	sqlite3_close_v2(roomDatabase);
}

/**
 * delete room information
*/
bool RoomBean::Delete(Room *room)
{
	char back_sql[SQL_LENGTH] = {};
	int id = room->getRoomId();

	sprintf_s(back_sql,
			  "DELETE FROM roombean WHERE roomId = %d",
			  id);
	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		std::cout << "[INFO] Room deleted.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to delete room.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

/**
 * update room information
*/
bool RoomBean::Update(Room *room)
{
	char back_sql[SQL_LENGTH] = {};
	int id = room->getRoomId();
	int tw = (int)room->getTargetW();
	int s = (int)room->getRoomState();
	double tt = room->getTargetT();
	if (tt == 0)
	{
		if (tw == 0)
		{
			sprintf_s(back_sql,
					  "UPDATE roombean\
				SET time=%d,\
				type=%d,\
				source=%d,\
				destination=%d,\
				queryType=%d,\
				responseType=%d,\
				state=%d\
				WHERE roomId = %d",
					  (int)room->getTime(),
					  (int)room->getType(),
					  (int)room->getSource(),
					  (int)room->getDestination(),
					  (int)room->getQueryType(),
					  (int)room->getResponseType(),
					  s,
					  id);
		}
		else if (s == 0)
		{
			sprintf_s(back_sql,
					  "UPDATE roombean\
				SET time=%d,\
				type=%d,\
				source=%d,\
				destination=%d,\
				queryType=%d,\
				responseType=%d,\
				targetW=%d,\
				nowW=%d\
				WHERE roomId = %d",
					  (int)room->getTime(),
					  (int)room->getType(),
					  (int)room->getSource(),
					  (int)room->getDestination(),
					  (int)room->getQueryType(),
					  (int)room->getResponseType(),
					  (int)room->getTargetW(),
					  (int)room->getTargetW(),
					  id);
		}
		else
		{
			std::cout << "[ERROR] Failed to edit room info: wrong query.\n";
			return false;
		}
	}
	else if (tt != 0 && (tw != 0 || s != 0))
	{
		std::cout << "[ERROR] Failed to edit room info: wrong query.\n";
		return false;
	}
	else
	{
		sprintf_s(back_sql,
				  "UPDATE roombean\
			SET time=%d,\
			type=%d,\
			source=%d,\
			destination=%d,\
			queryType=%d,\
			responseType=%d,\
			targetT=%lf\
			WHERE roomId = %d",
				  (int)room->getTime(),
				  (int)room->getType(),
				  (int)room->getSource(),
				  (int)room->getDestination(),
				  (int)room->getQueryType(),
				  (int)room->getResponseType(),
				  room->getTargetT(),
				  id);
	}

	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		std::cout << "[INFO] Room updateded.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to update room.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

/**
 * update room power
*/
bool RoomBean::Update_power(Room *room)
{
	char back_sql[SQL_LENGTH] = {};
	int id = room->getRoomId();
	int p = room->getPower();

	if (p == 1)
	{
		sprintf_s(back_sql,
				  "UPDATE roombean\
			SET time=%d,\
			source=%d,\
			power=%d\
			WHERE roomId = %d",
				  (int)room->getTime(),
				  (int)room->getSource(),
				  room->getPower(),
				  id);
	}
	else if (p == 0)
	{
		sprintf_s(back_sql,
				  "UPDATE roombean\
			SET time=%d,\
			source=%d,\
			state=%d,\
			power=%d\
			WHERE roomId = %d",
				  (int)room->getTime(),
				  (int)room->getSource(),
				  (int)room->getRoomState(),
				  room->getPower(),
				  id);
	}
	else
	{
		std::cout << "[ERROR] Failed to update room.\n";
		return false;
	}

	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		std::cout << "[INFO] Room updateded.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to update room.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

/**
 * insert room temperature
*/
bool RoomBean::Update_temp(Room *room)
{
	char back_sql[SQL_LENGTH] = {};
	int id = room->getRoomId();

	sprintf_s(back_sql,
			  "UPDATE roombean\
		SET time=%d,\
		source=%d,\
		nowT=%lf\
		WHERE roomId = %d",
			  (int)room->getTime(),
			  (int)room->getSource(),
			  room->getCurrentT(),
			  id);
	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		std::cout << "[INFO] Room updateded.\n";
		sqlite3_step(stmt);
	}
	else
	{
		std::cout << "[ERROR] Failed to update room.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

/**
 * query room information
*/
bool RoomBean::Query(Room *room)
{
	char back_sql[SQL_LENGTH] = {};
	int id = room->getRoomId();

	sprintf_s(back_sql,
			  "SELECT \
		time,state,targetT,initT,nowW,nowT,fee,power\
		FROM roombean\
		WHERE roomId = %d",
			  id);
	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		if (sqlite3_step(stmt) == SQLITE_ROW)
		{
			do
			{
				room->setTime(sqlite3_column_int(stmt, 0));
				room->setRoomState(RoomState(sqlite3_column_int(stmt, 1)));
				room->setTargetT(sqlite3_column_double(stmt, 2));
				room->setInitT(sqlite3_column_double(stmt, 3));
				room->setCurrentW(FanSpeed(sqlite3_column_int(stmt, 4)));
				room->setCurrentT(sqlite3_column_double(stmt, 5));
				room->setBill(sqlite3_column_double(stmt, 6));
				room->setPower(sqlite3_column_int(stmt, 7));
			} while (sqlite3_step(stmt) == SQLITE_ROW);
			std::cout << "[INFO] Room queried.\n";
		}
		else
		{
			std::cout << "[ERROR] Failed to query room bean.\n";
			return false;
		}
	}
	else
	{
		std::cout << "[ERROR] Failed to query room bean.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}

/**
 * query room ids
*/
bool RoomBean::Query(std::vector<int> &roomlist)
{
	char back_sql[SQL_LENGTH] = {};

	sprintf_s(back_sql,
			  "SELECT roomId FROM roombean");
	int result = sqlite3_prepare_v2(roomDatabase, back_sql, -1, &(stmt), NULL);

	if (result == SQLITE_OK)
	{
		while (sqlite3_step(stmt) == SQLITE_ROW)
		{
			roomlist.push_back(sqlite3_column_int(stmt, 0));
		}
		std::cout << "[INFO] Room queried.\n";
	}
	else
	{
		std::cout << "[ERROR] Failed to query room bean.\n";
		return false;
	}

	sqlite3_finalize(stmt);
	return true;
}
